include_directories(.)

# Because these tests use type parameterization, unfortunately we need to
# preprocess *before* running the pFUnit preprocessor, then again *after*.
if(${CMAKE_C_COMPILER_ID} STREQUAL GNU OR ${CMAKE_C_COMPILER_ID} STREQUAL Clang)
  function(make_cpp_command varname start_file end_file)
    set(${varname} ${CMAKE_C_COMPILER} -E -x c ${start_file} -o ${end_file}
      PARENT_SCOPE)
  endfunction()
elseif(${CMAKE_C_COMPILER_ID} STREQUAL Intel)
  function(make_cpp_command varname start_file end_file)
    set(${varname} "${CMAKE_C_COMPILER} -E ${start_file} -o ${end_file}"
      PARENT_SCOPE)
  endfunction()
elseif(${CMAKE_C_COMPILER_ID} STREQUAL XL)
  function(make_cpp_command varname start_file end_file)
    get_filename_component(start_base ${start_file} NAME)
    string(REGEX REPLACE "\\.[^.]+$" ".i" cpp_output ${start_base})
    # Unfortunately, the C preprocessor doesn't like Fortran syntax, and
    # returns a non-zero error code even though it succeeds. Use "|| :" to
    # tell CMake that the command succeeded.
    set(${varname} ${CMAKE_C_COMPILER} -E ${start_file} > ${end_file} || :
      PARENT_SCOPE)
  endfunction()
endif()

# Function to preprocess the input to the output with the C preprocessor.
# Any extra arguments are interpreted as header files that preprocessing
# depends on. Unfortunately, we lose CMake's intrinsic capability to
# track included files as dependencies.
function(c_preprocess in_file out_file)
  if(IS_ABSOLUTE "${in_file}")
    set(start_file "${in_file}")
  else()
    set(start_file "${CMAKE_CURRENT_SOURCE_DIR}/${in_file}")
  endif()
  if(IS_ABSOLUTE "${out_file}")
    set(end_file "${out_file}")
  else()
    set(end_file "${CMAKE_CURRENT_BINARY_DIR}/${out_file}")
  endif()
  set(includes ${ARGN})

  make_cpp_command(cpp_command ${start_file} ${end_file})
  separate_arguments(cpp_command)
  add_custom_command(
    OUTPUT ${end_file}
    COMMAND ${cpp_command}
    DEPENDS ${start_file} ${includes}
    )

endfunction()

# Included in tests we preprocess here.
set(test_include
  ${CMAKE_CURRENT_SOURCE_DIR}/dynamic_vector_base_tests.inc)

# Clear before loop below.
unset(pf_sources)

# File with int_ptr type.
set(test_sources ptr_wrapper.F90)

set(sources_needed shr_kind_mod.F90 shr_infnan_mod.F90
  shr_strconvert_mod.F90 shr_log_mod.F90)
extract_sources("${sources_needed}" "${share_sources}" test_sources)

# Loop over type tests.
#
# The idea is that integer tests an intrinsic type, real(r8) is a type with
# a kind, character is special because of its length and substring syntax,
# and int_ptr is a simple derived type.

# "character16" could be in the following list, but right now it is broken
# on multiple compilers due to compiler bugs.
foreach(type IN ITEMS integer r8 int_ptr)
c_preprocess(${type}_vector_tests.pf.in ${type}_vector_tests.pf
  ${test_include})
  list(APPEND pf_sources
    ${CMAKE_CURRENT_BINARY_DIR}/${type}_vector_tests.pf)
  list(APPEND test_sources
    dynamic_vector_${type}.F90)
endforeach()

create_pFUnit_test(dynamic_vector dynamic_vector_exe
  "${pf_sources}" "${test_sources}")

declare_generated_dependencies(dynamic_vector_exe "${share_genf90_sources}")
